package com.pdlocation.service;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import com.pdlocation.PdLocationUtils;
import com.pdlocation.model.LocationPoint;
import com.pdlocation.repository.DataRepository;
import com.pdlocation.util.KalmanFilter;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

public class TrackingService extends Service {
    private static final String TAG = "TrackingService";
    private static final int NOTIFICATION_ID = 12345;
    private static final String CHANNEL_ID = "location_tracking_channel";
    public static final String ACTION_LOCATION_UPDATED = "com.pdgps.service.LOCATION_UPDATED";
    public static final String EXTRA_LOCATION = "location";

    private LocationManager locationManager;
    private LocationListener gpsListener, networkListener;
    private NotificationManager notificationManager;

    private Location lastGpsLocation, lastNetworkLocation;
    private int satelliteCount = 0;
    private boolean isDeviceStationary = false;

    // 卡尔曼滤波器
    private final KalmanFilter latFilter = new KalmanFilter();
    private final KalmanFilter lngFilter = new KalmanFilter();
    private final KalmanFilter altFilter = new KalmanFilter();
    private boolean isFilterInitialized = false;

    // 定位状态
    public static final int STATUS_INIT = 0;
    public static final int STATUS_SEARCHING = 1;
    public static final int STATUS_LOW_ACCURACY = 2;
    public static final int STATUS_MEDIUM_ACCURACY = 3;
    public static final int STATUS_HIGH_ACCURACY = 4;
    private int locationStatus = STATUS_INIT;

    private DataRepository repository;

    private Geocoder geocoder;


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "服务创建");
        repository = DataRepository.getInstance();

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        createNotificationChannel();

        initSensors();
        setupLocationListeners();

        geocoder = new Geocoder(this, Locale.getDefault());
        //当前无法使用这个
//        requestAGPSData();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 将Service设为前台状态（显示永久通知）
        startForeground(NOTIFICATION_ID, createNotification());
        return START_STICKY; // 系统杀死后尝试重启Service
    }

    @SuppressLint("MissingPermission")
    private void setupLocationListeners() {
        // 使用Criteria选择最佳定位提供者
        android.location.Criteria criteria = new android.location.Criteria();
        criteria.setAccuracy(android.location.Criteria.ACCURACY_FINE);
        criteria.setAltitudeRequired(true);
        criteria.setBearingRequired(false);
        criteria.setSpeedRequired(false);
        criteria.setCostAllowed(true);
        criteria.setPowerRequirement(android.location.Criteria.POWER_HIGH);

        // GPS定位监听器
        gpsListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                Log.d(TAG, "GPS位置更新: " + location);
                processLocationUpdate(location, true);
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
                Log.d(TAG, "GPS状态变化: " + status);
                switch (status) {
                    case LocationProvider.AVAILABLE:
                        locationStatus = STATUS_SEARCHING;
                        break;
                    case LocationProvider.OUT_OF_SERVICE:
                    case LocationProvider.TEMPORARILY_UNAVAILABLE:
                        locationStatus = STATUS_SEARCHING;
                        break;
                }
                updateNotification();
            }

            @Override
            public void onProviderEnabled(String provider) {
                Log.d(TAG, "GPS提供者已启用");
            }

            @Override
            public void onProviderDisabled(String provider) {
                Log.d(TAG, "GPS提供者已禁用");
                locationStatus = STATUS_SEARCHING;
                updateNotification();
            }
        };

        // 网络定位监听器
        networkListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                Log.d(TAG, "网络位置更新: " + location);
                processLocationUpdate(location, false);
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
            }

            @Override
            public void onProviderEnabled(String provider) {
            }

            @Override
            public void onProviderDisabled(String provider) {
            }
        };

        // 注册定位监听器
        try {
            if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
                locationManager.requestLocationUpdates(
                        LocationManager.GPS_PROVIDER,
                        1000,      // 1秒更新间隔
                        0,         // 1米最小位移
                        gpsListener
                );

                // 注册GPS状态监听器以获取卫星数量
                locationManager.addGpsStatusListener(gpsStatusListener);
            }

            if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
                locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER,
                        1000,      // 5秒更新间隔
                        0,        // 10米最小位移
                        networkListener
                );
            }
        } catch (SecurityException e) {
            Log.e(TAG, "注册定位监听器失败", e);
        }
    }

    // GPS状态监听器
    // 替换原有的gpsStatusListener
    private GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
        @Override
        public void onGpsStatusChanged(int event) {
            try {
                GpsStatus gpsStatus = locationManager.getGpsStatus(null);
                if (gpsStatus != null) {
                    switch (event) {
                        case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                            // 获取可见卫星数量
                            int count = 0;
                            int usedInFix = 0;
                            float bestSnr = 0; // 最佳信噪比

                            Iterable<GpsSatellite> satellites = gpsStatus.getSatellites();
                            Iterator<GpsSatellite> it = satellites.iterator();

                            while (it.hasNext()) {
                                GpsSatellite satellite = it.next();
                                count++;

                                // 记录最佳信噪比
                                if (satellite.getSnr() > bestSnr) {
                                    bestSnr = satellite.getSnr();
                                }

                                if (satellite.usedInFix()) {
                                    usedInFix++;
                                }
                            }

                            satelliteCount = usedInFix;
                            Log.d(TAG, "可见卫星: " + count + ", 用于定位: " + usedInFix + ", 最佳信噪比: " + bestSnr);

                            // 如果可见卫星多但用于定位的少，可能是信号质量问题
                            if (count >= 4 && usedInFix == 0) {
                                Log.w(TAG, "可见卫星数量充足，但没有用于定位的卫星，可能是信号质量问题");
                            }
                            break;

                        case GpsStatus.GPS_EVENT_FIRST_FIX:
                            Log.d(TAG, "首次定位成功，耗时: " + gpsStatus.getTimeToFirstFix() + "毫秒");
                            break;
                    }
                }
            } catch (SecurityException e) {
                Log.e(TAG, "获取GPS状态失败", e);
            }
        }
    };

    private void processLocationUpdate(Location location, boolean isGps) {
        // 应用卡尔曼滤波
        applyKalmanFilter(location);

        // 异常值检测
        if (!isLocationValid(location, isGps ? lastGpsLocation : lastNetworkLocation)) {
            Log.w(TAG, "检测到异常位置，已过滤: " + location);
            return;
        }

        // 更新最后位置
        if (isGps) {
            lastGpsLocation = location;
        } else {
            lastNetworkLocation = location;
        }

        // 融合多源定位数据
        LocationPoint fusedLocation = fuseLocations(lastGpsLocation, lastNetworkLocation);
        if (fusedLocation != null) {
            broadcastLocation(fusedLocation);
            updateLocationStatus();
            updateNotification();
        }
    }

    private void applyKalmanFilter(Location location) {
        if (!isFilterInitialized) {
            latFilter.init(location.getLatitude());
            lngFilter.init(location.getLongitude());
            if (location.hasAltitude()) {
                altFilter.init(location.getAltitude());
            }
            isFilterInitialized = true;
        } else {
            // 根据设备状态调整卡尔曼滤波器参数
            if (isDeviceStationary) {
                latFilter.setProcessNoise(0.000001);
                lngFilter.setProcessNoise(0.000001);
                if (location.hasAltitude()) {
                    altFilter.setProcessNoise(0.000001);
                }
            } else {
                latFilter.setProcessNoise(0.00001);
                lngFilter.setProcessNoise(0.00001);
                if (location.hasAltitude()) {
                    altFilter.setProcessNoise(0.00001);
                }
            }

            // 应用滤波
            double filteredLat = latFilter.filter(location.getLatitude());
            double filteredLng = lngFilter.filter(location.getLongitude());

            location.setLatitude(filteredLat);
            location.setLongitude(filteredLng);

            if (location.hasAltitude()) {
                double filteredAlt = altFilter.filter(location.getAltitude());
                location.setAltitude(filteredAlt);
            }
        }
    }

    private boolean isLocationValid(Location newLocation, Location lastLocation) {
        if (lastLocation == null) return true;

        // 计算两点之间的距离（米）
        float[] results = new float[1];
        Location.distanceBetween(
                lastLocation.getLatitude(), lastLocation.getLongitude(),
                newLocation.getLatitude(), newLocation.getLongitude(),
                results
        );
        float distance = results[0];

        // 计算时间差（秒）
        long timeDiff = (newLocation.getTime() - lastLocation.getTime()) / 1000;
        timeDiff = Math.max(1, timeDiff); // 避免除零错误

        // 计算速度（米/秒）
        float speed = distance / timeDiff;

        // 根据设备状态调整速度阈值
        float maxSpeed = isDeviceStationary ? 2 : 15; // 静止时允许2米/秒的误差

        // 检查速度是否合理
        boolean isSpeedValid = speed < maxSpeed;

        // 检查精度是否合理
        boolean isAccuracyValid = newLocation.getAccuracy() < 150;

        // 检查坐标范围
        boolean isCoordinateValid =
                newLocation.getLatitude() > -90 && newLocation.getLatitude() < 90 &&
                        newLocation.getLongitude() > -180 && newLocation.getLongitude() < 180;

        // 检查海拔变化是否合理（如果有海拔数据）
        boolean isAltitudeValid = true;
        if (newLocation.hasAltitude() && lastLocation.hasAltitude()) {
            float altitudeDiff = (float) Math.abs(newLocation.getAltitude() - lastLocation.getAltitude());
            float maxAltitudeChange = isDeviceStationary ? 5 : 30; // 米/秒
            isAltitudeValid = altitudeDiff < maxAltitudeChange;
        }

        return isSpeedValid && isAccuracyValid && isCoordinateValid && isAltitudeValid;
    }

    private LocationPoint fuseLocations(Location gpsLocation, Location networkLocation) {
        // 1. 优先使用高精度GPS定位
        if (gpsLocation != null && gpsLocation.getAccuracy() < 15) {
            return createLocationPoint(gpsLocation, 0); // 0:GPS
        }

        // 2. 检查GPS和网络定位的质量
        boolean isGpsGood = gpsLocation != null && gpsLocation.getAccuracy() < 50;
        boolean isNetworkGood = networkLocation != null && networkLocation.getAccuracy() < 200;

        // 3. 加权融合算法
        if (isGpsGood && isNetworkGood) {
            // 计算权重（考虑精度和时间）
            long currentTime = System.currentTimeMillis();
            double gpsTimeWeight = Math.exp(-(currentTime - gpsLocation.getTime()) / 30000.0);
            double networkTimeWeight = Math.exp(-(currentTime - networkLocation.getTime()) / 30000.0);

            double gpsAccuracyWeight = 1.0 - (gpsLocation.getAccuracy() / 100);
            double networkAccuracyWeight = 1.0 - (networkLocation.getAccuracy() / 500);

            // 综合权重
            double gpsWeight = gpsTimeWeight * gpsAccuracyWeight;
            double networkWeight = networkTimeWeight * networkAccuracyWeight;

            // 归一化权重
            double totalWeight = gpsWeight + networkWeight;
            if (totalWeight > 0) {
                gpsWeight /= totalWeight;
                networkWeight /= totalWeight;
            }

            // 融合坐标
            double fusedLat = gpsLocation.getLatitude() * gpsWeight +
                    networkLocation.getLatitude() * networkWeight;

            double fusedLng = gpsLocation.getLongitude() * gpsWeight +
                    networkLocation.getLongitude() * networkWeight;

            // 融合海拔（如果两者都有）
            double fusedAlt = 0;
            boolean hasAltitude = false;
            if (gpsLocation.hasAltitude() && networkLocation.hasAltitude()) {
                fusedAlt = gpsLocation.getAltitude() * gpsWeight +
                        networkLocation.getAltitude() * networkWeight;
                hasAltitude = true;
            } else if (gpsLocation.hasAltitude()) {
                fusedAlt = gpsLocation.getAltitude();
                hasAltitude = true;
            }

            // 计算融合精度
            float fusedAccuracy = (float) (gpsLocation.getAccuracy() * gpsWeight +
                    networkLocation.getAccuracy() * networkWeight);
            String addressFromLocation = getAddressFromLocation(fusedLat, fusedLng);
            // 创建融合后的位置点
            return new LocationPoint(
                    fusedLat,
                    fusedLng,
                    fusedAlt,
                    fusedAccuracy,
                    System.currentTimeMillis(),
                    2, // 2:Fused
                    satelliteCount,
                    hasAltitude,
                    addressFromLocation
            );
        }

        // 4. 使用可用的最佳定位
        if (isGpsGood) {
            return createLocationPoint(gpsLocation, 0);
        }

        if (isNetworkGood) {
            return createLocationPoint(networkLocation, 1);
        }

        return null;
    }

    private LocationPoint createLocationPoint(Location location, int source) {
        String addressFromLocation = getAddressFromLocation(location.getLatitude(), location.getLongitude());
        return new LocationPoint(
                location.getLatitude(),
                location.getLongitude(),
                location.hasAltitude() ? location.getAltitude() : 0,
                location.getAccuracy(),
                System.currentTimeMillis(),
                source,
                source == 0 ? satelliteCount : 0,
                location.hasAltitude(),
                addressFromLocation
        );
    }

    private void broadcastLocation(LocationPoint location) {
//        Intent intent = new Intent(ACTION_LOCATION_UPDATED);
//        intent.putExtra(EXTRA_LOCATION, location);
//        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
        // 更新 LiveData
        // 模拟定期生成数据
        repository.updateData(location);
    }

    private void updateLocationStatus() {
        if (lastGpsLocation == null && lastNetworkLocation == null) {
            locationStatus = STATUS_SEARCHING;
            return;
        }

        Location bestLocation = lastGpsLocation != null ? lastGpsLocation : lastNetworkLocation;
        if (bestLocation.getAccuracy() < 10) {
            locationStatus = STATUS_HIGH_ACCURACY;
        } else if (bestLocation.getAccuracy() < 30) {
            locationStatus = STATUS_MEDIUM_ACCURACY;
        } else {
            locationStatus = STATUS_LOW_ACCURACY;
        }
    }

    // 初始化传感器
    private void initSensors() {
        SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

        // 加速度计用于检测设备是否静止
        Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        sensorManager.registerListener(new SensorEventListener() {
            @Override
            public void onSensorChanged(SensorEvent event) {
                float x = event.values[0];
                float y = event.values[1];
                float z = event.values[2];
                float acceleration = (float) Math.sqrt(x * x + y * y + z * z);
                isDeviceStationary = acceleration < 1.0;
            }

            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
            }
        }, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
    }

    private Notification createNotification() {
        String statusText = "定位中...";
        switch (locationStatus) {
            case STATUS_HIGH_ACCURACY:
                statusText = "高精度定位";
                break;
            case STATUS_MEDIUM_ACCURACY:
                statusText = "中等精度定位";
                break;
            case STATUS_LOW_ACCURACY:
                statusText = "低精度定位";
                break;
            case STATUS_SEARCHING:
                statusText = "搜索卫星中";
                break;
        }
        PendingIntent pendingIntent = null;
        if (PdLocationUtils.clazz != null) {
            Intent notificationIntent = new Intent(this, PdLocationUtils.clazz);
            pendingIntent = PendingIntent.getActivity(
                    this, 0, notificationIntent,
                    Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ?
                            PendingIntent.FLAG_IMMUTABLE : 0
            );
        }

        if (pendingIntent != null) {
            return new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentTitle("定位服务正在运行")
                    .setContentText(statusText)
                    .setSmallIcon(PdLocationUtils.notificationLogo)
                    .setContentIntent(pendingIntent)
                    .setPriority(NotificationCompat.PRIORITY_LOW)
                    .setOngoing(true)//// 设为永久通知，不可清除
                    .build();
        } else {
            return new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentTitle("定位服务正在运行")
                    .setContentText(statusText)
                    .setSmallIcon(PdLocationUtils.notificationLogo)
                    .setPriority(NotificationCompat.PRIORITY_LOW)
                    .setOngoing(true)//// 设为永久通知，不可清除
                    .build();
        }


    }

    private void updateNotification() {
        if (notificationManager != null) {
            notificationManager.notify(NOTIFICATION_ID, createNotification());
        }
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    "定位服务",
                    NotificationManager.IMPORTANCE_LOW
            );
            notificationManager.createNotificationChannel(channel);
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "服务销毁");

        // 移除定位监听器
        if (locationManager != null) {
            if (gpsListener != null) {
                locationManager.removeUpdates(gpsListener);
                locationManager.removeGpsStatusListener(gpsStatusListener);
            }
            if (networkListener != null) {
                locationManager.removeUpdates(networkListener);
            }
        }
        stopForeground(true);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    // 根据经纬度获取地址
    private String getAddressFromLocation(double latitude, double longitude) {
        String myAddress = null;
        try {
            List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
            if (addresses != null && !addresses.isEmpty()) {
                Address address = addresses.get(0);
                StringBuilder addressString = new StringBuilder();

                // 拼接详细地址
                for (int i = 0; i <= address.getMaxAddressLineIndex(); i++) {
                    addressString.append(address.getAddressLine(i)).append("\n");
                }
                myAddress = addressString.toString();
                // 打印或者显示地址
                Log.d("Location", "Address: " + addressString.toString());
            } else {
                Log.d("Location", "No address found");
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.d("Location", "Geocoder error: " + e.getMessage());
        }
        return myAddress;
    }
}
